#ifndef HITTABLE_H
#define HITTABLE_H

#include "../ray.h"
#include "../interval.h"
#include "../aabb.h"

class material;

class hit_record {
public:
	point3 p;
	vec3 normal;
	double t;
	double u;
	double v;
	bool front_face;
	std::shared_ptr<material> mat;

	void set_face_normal(const ray& r, const vec3& outward_normal) {
		// Sets the hit record normal vector.
		// NOTE: the parameter `outward_normal` is assumed to have unit length.

		front_face = dot(r.direction(), outward_normal) < 0;
		normal = front_face ? outward_normal : -outward_normal;
	}
};

class hittable {
public:
	virtual ~hittable() = default;

	virtual bool hit(const ray& r, interval ray_t, hit_record& rec) const = 0;

	virtual aabb bounding_box() const = 0;

	virtual double pdf_value(const point3& origin, const vec3& direction) const {
		return 0.0;
	}

	virtual vec3 random(const point3& origin) const {
		return vec3(1, 0, 0);
	}
};

class translate : public hittable {
public:
	translate(std::shared_ptr<hittable> object, const vec3& offset)
		: object(object), offset(offset)
	{
		bbox = object->bounding_box() + offset;
	}

	bool hit(const ray& r, interval ray_t, hit_record& rec) const override;

	aabb bounding_box() const override { return bbox; }

private:
	std::shared_ptr<hittable> object;// 要平移的对象
	vec3 offset;
	aabb bbox;
};

class rotate_y : public hittable {
public:
	rotate_y(std::shared_ptr<hittable> object, double angle);

	bool hit(const ray& r, interval ray_t, hit_record& rec) const override;
	aabb bounding_box() const override { return bbox; }

private:
	std::shared_ptr<hittable> object;
	double sin_theta;
	double cos_theta;
	aabb bbox;
};

#endif